package com.cloudea.lotus.utils;

import com.cloudea.lotus.bo.UserInfo;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;

import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.List;

public class JWTUtil {
    private static PrivateKey privateKey = null;
    private static String publicKey = null;

    static {
        // 生成公钥和私钥匙
        KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.ES256);
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        JWTUtil.privateKey = privateKey;
        JWTUtil.publicKey = Base64.getEncoder().encodeToString(publicKey.getEncoded());
    }

    /**
     * 把本机的公钥返回
     * @return 本机的公钥
     */
    public static String getPublicKey(){
        return publicKey;
    }

    /**
     * 把用户信息签名成JWT
     * @param userInfo 要签名的用户信息
     * @param expireTime 过期时间（毫秒）
     * @return 一个TOKEN
     */
    public static String  generate(UserInfo userInfo, long expireTime){ //毫秒
        String jwt = Jwts.builder()
                .setId(userInfo.getUserId())
                .claim("roles", userInfo.getRoles())
                .claim("perms", userInfo.getPerms())
                .setExpiration(new Date(new Date().getTime() + expireTime))
                .signWith(privateKey)
                .compact();
        return jwt;
    }

    /**
     * 把接收一到的JWT字符串利用已有的公钥解密
     * @param jwt  接收到的字符串
     * @param publicKeys 备选公钥
     * @return 解释完成的用户信息，如果所有公钥都不能解开，则返回null
     */
    public static UserInfo restore(String jwt, List<String> publicKeys) throws Exception{
        SigningKeyResolver resolver = new SigningKeyResolverAdapter();
        for(String publicKey : publicKeys){
            PublicKey p = null;
            try {
                KeyFactory keyFactory = KeyFactory.getInstance("EC");
                X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey));
                p = keyFactory.generatePublic(x509EncodedKeySpec);
                Jws<Claims> claimsJws = Jwts.parserBuilder().setSigningKey(p).build().parseClaimsJws(jwt);
                Claims claims = claimsJws.getBody();
                UserInfo userInfo = new UserInfo();
                userInfo.setUserId(claims.getId());
                userInfo.setRoles(claims.get("roles", List.class));
                userInfo.setPerms(claims.get("perms", List.class));
                return userInfo;
            }catch (ExpiredJwtException e){
                throw new RuntimeException("TOKEN 已经过期");
            } catch (Exception e) {
                //e.printStackTrace();
            }
        }
        throw new RuntimeException("不是有效的TOKEN");
    }
}
